/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 adv_object_strings.cpp

	$Header: /heroes4/adv_object_strings.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )
#include "adv_object_strings.h"

#include <map>
#include <vector>
#include "adv_object_type.h"
#include "adv_object_type_properties.h"
#include "enum_operations.h"
#include "qualified_adv_object_type.h"
#include "table.h"
#include "table_ptr.h"

namespace
{
	// ---------------------------------------------
	// map of string to string
	// ---------------------------------------------
	class t_string_map : public std::map< std::string, std::string, t_string_insensitive_less >
	{
	};

	// ---------------------------------------------
	// list of strings for an minor type of an adventure object
	// ---------------------------------------------
	class t_minor_type_strings
	{
	public:
		t_minor_type_strings( t_adv_object_type_properties const& parent, int value );

		void add( std::string const& subtype_string, std::string const& keyword, 
			      std::string const& value );

		std::string get_string( t_qualified_adv_object_type const& type, std::string keyword  ) const;
	protected:
		t_adv_object_major_subtype_properties const* m_properties;
		t_string_map								 m_strings;
		std::vector<t_string_map>				     m_subtype_strings;
	};

	// ---------------------------------------------
	// list of strings for an adventure object
	// ---------------------------------------------
	class t_major_type_strings
	{
	public:
		t_major_type_strings( t_adv_object_type type );

		void add( std::string const& minor_type_string, std::string const& subtype_string, 
			      std::string const& keyword, std::string const& value );

		std::string get_string( t_qualified_adv_object_type const& type, std::string keyword  ) const;
	protected:
		t_adv_object_type                 m_type;
		t_string_map                      m_strings;
		std::vector<t_minor_type_strings> m_minor_type_strings;
	};


	// ---------------------------------------------
	// list of strings for all adventure objects
	// ---------------------------------------------
	class t_adv_object_strings
	{
	public:
		t_adv_object_strings();

		std::string get_string( t_qualified_adv_object_type const& type, std::string keyword ) const;
	protected:
		std::vector<t_major_type_strings> m_strings;
	};

	enum {
		k_column_major_type,
		k_column_minor_type,
		k_column_subtype,
		k_column_keyword,
		k_column_text
	};

}; // unnamed namespace

// ---------------------------------------------
// list of strings for an minor type of an adventure object
// ---------------------------------------------
t_minor_type_strings::t_minor_type_strings( t_adv_object_type_properties const& parent,
                                            int value )
				    : m_properties( &parent.get_subtype_properties( value ) )
{
	if (m_properties->has_subtypes())
	{
		m_subtype_strings.resize( m_properties->get_subtype_count() );
	}
}

// ---------------------------------------------
// list of strings for an minor type of an adventure object
// ---------------------------------------------
void t_minor_type_strings::add( std::string const& subtype_string, 
                                std::string const& keyword,  std::string const& value )
{
	int subtype = -1;

	if (!subtype_string.empty())
		subtype = m_properties->get_subtype_value( subtype_string );
	
	if (subtype < 0)
		m_strings[keyword] = value;
	else
		m_subtype_strings[subtype][keyword] = value;
}

// ---------------------------------------------
// list of strings for an minor type of an adventure object
// ---------------------------------------------
std::string t_minor_type_strings::get_string( t_qualified_adv_object_type const& type, 
											  std::string keyword  ) const
{
	int						     subtype = type.minor_subtype();
	t_string_map::const_iterator result;

	if (subtype < (int)m_subtype_strings.size())
	{
		result = m_subtype_strings[subtype].find( keyword );
		if (result != m_subtype_strings[subtype].end())
			return result->second;
	}
	result = m_strings.find( keyword );
	if (result != m_strings.end())
		return result->second;
	return "";
}

// ---------------------------------------------
// list of strings for an adventure object
// ---------------------------------------------
t_major_type_strings::t_major_type_strings( t_adv_object_type type )
{
	t_adv_object_type_properties const& properties = get_adv_object_type_properties( type );

	m_type = type;
	if (properties.has_subtypes())
	{
		int i;

		for (i = 0; i < properties.get_subtype_count(); i++)
			m_minor_type_strings.push_back( t_minor_type_strings( properties, i ) );
	}
}	

// ---------------------------------------------
// list of strings for an adventure object
// ---------------------------------------------
void t_major_type_strings::add( std::string const& minor_type_string,
							    std::string const& subtype_string, std::string const& keyword,
								std::string const& value )
{
	int minor_type = -1;

	if (!minor_type_string.empty())
		minor_type = get_adv_object_type_properties( m_type ).get_subtype_value( minor_type_string );

	if (minor_type < 0)
		m_strings[keyword] = value;
	else
		m_minor_type_strings[minor_type].add( subtype_string, keyword, value );
}

// ---------------------------------------------
// list of strings for an adventure object
// ---------------------------------------------
std::string t_major_type_strings::get_string( t_qualified_adv_object_type const& type, 
											  std::string keyword  ) const
{
	std::string text;
	int         minor_type = type.major_subtype();

	if (minor_type < (int)m_minor_type_strings.size())
	{
		text = m_minor_type_strings[minor_type].get_string( type, keyword );
		if (!text.empty())
			return text;
	}

	t_string_map::const_iterator result = m_strings.find( keyword );

	if (result != m_strings.end())
		return result->second;
	return "";
}

// ---------------------------------------------
// list of strings for all adventure objects
// ---------------------------------------------
t_adv_object_strings::t_adv_object_strings()
{
	t_adv_object_type   type;
	t_table_cache       adv_object_table( "adventure object" );
	t_table_ptr			table = adv_object_table.get();
	std::string			major_type_string;
	t_table::iterator	line;

	for (type = t_adv_object_type(0); type < k_adv_object_type_count; enum_incr( type ))
	{
		m_strings.push_back( t_major_type_strings( type ) );
	}

	// skip header
	line = table->begin();
	line++;
	for (; line != table->end(); line++)
	{
		if (line->size() == 0)
			continue;

		major_type_string = (*line)[k_column_major_type];
		if (major_type_string.empty())
			continue;

		type = get_adv_object_type( major_type_string );
		if (type == k_adv_object_nothing)
			continue;

		m_strings[type].add( (*line)[k_column_minor_type], (*line)[k_column_subtype],
			                 (*line)[k_column_keyword],    (*line)[k_column_text] );
	}
}

// ---------------------------------------------
// list of strings for all adventure objects
// ---------------------------------------------
inline std::string t_adv_object_strings::get_string( t_qualified_adv_object_type const& type, 
											  std::string keyword ) const
{
	t_adv_object_type object_type = type.get();

	return m_strings[type].get_string( type, keyword );
}


std::string get_string( t_qualified_adv_object_type const& type, std::string keyword )
{
	static t_adv_object_strings strings;

	return strings.get_string( type, keyword );
}

std::string get_name( t_qualified_adv_object_type const& type )
{
	return get_string( type, "name" );
}
